/*

$Id: nvclib.c 6 2009-10-15 06:30:15Z alex.mobilebi $
$Date: 2009-10-15 06:30:15 +0000 (Thu, 15 Oct 2009) $
$Author: alex.mobilebi $
$Revision: 6 $

Copyright(C) 2009 Alex Lee(alex@mobilebi.com)

*/

#include "nvclib_core.h"
#include "DS26519_regs.h"
#include "DS31256_regs.h"

#define NV_IOC_MAGIC           'x'
#define NV_IOC_MAXNR           8
#define NV_IOC_WRITE_REG       _IOW(NV_IOC_MAGIC, 1, int)
#define NV_IOC_WRITE_REG_IS  _IOW(NV_IOC_MAGIC, 2, int)
#define NV_IOC_READ_REG        _IOR(NV_IOC_MAGIC, 3, int)
#define NV_IOC_RESET_PCI       _IO(NV_IOC_MAGIC, 4)
#define NV_IOC_RESET_LOCAL     _IO(NV_IOC_MAGIC, 5)
#define NV_IOC_DUMP            _IO(NV_IOC_MAGIC, 6)
#define NV_IOC_CONFIGDMA       _IO(NV_IOC_MAGIC, 7)

#define MK_ADD_VAL(add, val)   (((add)<<16)|((val) & 0xFFFF))

#define STATUS_OK 0x00
#define STATUS_RLOF 0x01
#define STATUS_RLOS 0x02
#define STATUS_RAIS 0x04
#define STATUS_RRAI 0x08
#define RLOFD_MASK 0x01
#define RLOSD_MASK 0x02
#define RAISD_MASK 0x04
#define RRAID_MASK 0x08
#define RLOFC_MASK 0x10
#define RLOSC_MASK 0x20
#define RAISC_MASK 0x40
#define RRAIC_MASK 0x80

#define OFF_LENGTH_HIGH             0
#define OFF_LENGTH_LOW              1
#define OFF_SECOND_D4               2
#define OFF_SECOND_D3               3
#define OFF_SECOND_D2               4
#define OFF_SECOND_D1               5
#define OFF_USECOND_D4              6
#define OFF_USECOND_D3              7
#define OFF_USECOND_D2              8
#define OFF_USECOND_D1              9
#define OFF_RESERVED                10
#define OFF_EVENT_TYPE              11
#define OFF_LINK_HIGH               12
#define OFF_LINK_LOW                13
#define OFF_BOARD                   12
#define OFF_PORT                    13
#define OFF_CHANNEL                 13
#define OFF_STATUS                  14
#define PACKET_HEAD_LEN             14

#define DUMP_REG_DS31256 0x0001
#define DUMP_REG_DS26519 0x0002

static unsigned int dump_regs_option = DUMP_REG_DS31256|DUMP_REG_DS26519;
static int logger;
static char * log_file = "nvc.log";
static char * log_flag[] = {"E","W","I", "D"};
static char log_level = DEBU;
static char log_msg[255];
static pthread_mutex_t nv_mutex = PTHREAD_MUTEX_INITIALIZER;
static char * dev[4][2] ={ {"/dev/nvc0","/dev/nvc1"},{"/dev/nvc2","/dev/nvc3"},{"/dev/nvc4","/dev/nvc5"},{"/dev/nvc6","/dev/nvc7"}};

static struct nvcBoard boards[MAX_BOARD_NUM];
static struct nvcPort ports[MAX_BOARD_NUM][MAX_PORT_NUM];
static struct nvcLink links[MAX_BOARD_NUM][MAX_CHANNEL_NUM];

static unsigned char running = 0;
static unsigned char initialized = 0;

static unsigned char cur_status = 0;

int set_port_config(const struct port_config conf)
{
	if(!is_initialized())
		return -ENOTINIT;

	if(!is_valid_port_config(conf))
		return -EINVALPORT;

	add_port_config(conf);
	write_log("add port config data", DEBU);
	return 0;
}
void init_config_data_struct(void)
{
	unsigned char board, port;
	unsigned short channel;

	write_log("begin to init config data struct", DEBU);
	for(board = 0; board < MAX_BOARD_NUM; board++)
	{
		boards[board].active = 0;
		boards[board].local = 0;
		boards[board].pci = 0;
		sprintf(log_msg, "init board %d config data struct", board);
		write_log(log_msg, DEBU);
		for(port = 0; port < MAX_PORT_NUM; port++)
			ports[board][port].active = 0;

		for(channel = 0; channel < MAX_CHANNEL_NUM; channel++)
			links[board][channel].active = 0;
	}
	initialized = 1;
	write_log("initialized config data struct", DEBU);
}
int set_link_config(const struct link_config conf)
{
	if(!is_initialized())
		return -ENOTINIT;

	if(!is_valid_link_config(conf))
		return -EINVALLINK;

	add_link_config(conf);
	write_log("add link config data", DEBU);
	return 0;
}
unsigned char is_valid_port_config(const struct port_config conf)
{
	return conf.board_id < MAX_BOARD_NUM 
		&& conf.port_id < MAX_PORT_NUM
	    && (conf.code_type == CODE_TYPE_NOHDB3 || conf.code_type == CODE_TYPE_HDB3)
		&& (conf.frame_type == FRAME_TYPE_DF || conf.frame_type == FRAME_TYPE_CRC4)
		&& (conf.impedance == PORT_IMP_MODE_75 || conf.impedance == PORT_IMP_MODE_100 || conf.impedance == PORT_IMP_MODE_110 || conf.impedance == PORT_IMP_MODE_120)
		&& (conf.port_mode == PORT_SYNC_MODE_T1 || conf.port_mode == PORT_SYNC_MODE_E1 || conf.port_mode == PORT_SYNC_MODE_4M || conf.port_mode == PORT_SYNC_MODE_8M)
		&& (conf.port_type == PORT_TYPE_E1 || conf.port_type == PORT_TYPE_T1);
}
void add_link_config(const struct link_config conf)
{
	unsigned short channel;
	int index = 1;
	channel = conf.port_id;
	while(links[conf.board_id][channel].active && channel < MAX_CHANNEL_NUM)
	{
		channel = conf.port_id + index * MAX_PORT_NUM;
		index++;
	}
	if(channel >= MAX_CHANNEL_NUM)
		return;
	links[conf.board_id][channel].active = 1;
	links[conf.board_id][channel].link = conf.link_id;
	links[conf.board_id][channel].port = conf.port_id;
	links[conf.board_id][channel].start_ts = conf.start_ts;
	links[conf.board_id][channel].ts_num = conf.ts_num;
}

unsigned char is_valid_link_config(const struct link_config conf)
{
	unsigned char ret;
	unsigned char port_type;
	port_type = ports[conf.board_id][conf.port_id].port_type;
	ret = conf.board_id < MAX_BOARD_NUM && conf.port_id < MAX_PORT_NUM && conf.link_id < MAX_LINK_NUM;
	if(port_type == PORT_TYPE_E1)
		ret = ret && conf.ts_num < 32;
	else if(port_type == PORT_TYPE_T1)
		ret = ret && conf.ts_num < 24;
	else ret = ret && conf.ts_num < MAX_TS_NUM;

	return ret && !is_link_full(conf.board_id);
}
unsigned char is_link_full(unsigned char board)
{
	unsigned char link_num;
	unsigned short index;
	link_num = 0;

	for(index = 0; index < MAX_CHANNEL_NUM; index++)
	{
		if(links[board][index].active)
			link_num++;
	}
	if(link_num < MAX_CHANNEL_NUM)
		return 0;
	else
		return 1;
}
void add_port_config(const struct port_config conf)
{
	unsigned char board, port;
	board = conf.board_id;
	port = conf.port_id;

	ports[board][port].active = 1;
	ports[board][port].board_id = board;
	ports[board][port].code_type = conf.code_type;
	ports[board][port].frame_type = conf.frame_type;
	ports[board][port].impedance = conf.impedance;
	ports[board][port].port_id = port;
	ports[board][port].port_type = conf.port_type;
	ports[board][port].port_mode = conf.port_mode;
}
unsigned char is_config(void)
{
	int board,port,channel;
	unsigned char ret;

	ret = 0;
	for(board = 0; board < MAX_BOARD_NUM; board++)
	{
		if(is_board_configured(board))
		{
			ret = 1;
			break;
		}
	}
	return ret;
}
unsigned char is_port_configured(unsigned char board, unsigned char port)
{
	return ports[board][port].active;
}
unsigned char is_link_configured(unsigned char board, unsigned char port)
{
	unsigned char ret;
	unsigned short channel;

	ret = 0;
	for(channel = 0; channel < MAX_CHANNEL_NUM; channel++)
	{
		if((links[board][channel].active) && (links[board][channel].port == port))
		{
			ret = 1;
			break;
		}
	}
	return ret;
}
unsigned char is_board_configured(unsigned char board)
{
	unsigned char port;
	unsigned char ret;
	ret = 0;
	for(port = 0; port < MAX_PORT_NUM; port++)
	{
		if(is_port_configured(board, port) && is_link_configured(board, port))
		{
			ret = 1;
			break;
		}
	}
	return ret;
}
int start(void)
{
	int err = 0;

	if(!is_config())
		return -ENOCONFIG;

	write_log("begin to open hardware devices ...", INFO);
	if((err = open_board()))
		return err;
	write_log("begin to initialize hardware ...", INFO);
	init_board();

	write_log("begin to start system ...", INFO);
	start_board();

	write_log("start successfully.", INFO);

	return 0;
}
int receive(unsigned char * buff, const unsigned int length)
{	
	int ret = 0;

	if(buff == NULL || length == 0)
		return -EINVALPARA;

	return read_data(buff, length);//2009年10月13日修改，目的为DS26519状态检测由轮询改为中断驱动

}
int read_data(unsigned char * buff, const unsigned int size)
{
	int ret = 0;
	unsigned char board,channel;
	unsigned char index = 0;
	
	index = 0;
	do
	{
		if(boards[index].active)		
		{
			if((ret = read(boards[index].pci, (unsigned int *)buff, size)) > 0)
			{
				if(buff[OFF_EVENT_TYPE] != PACKET_TYPE_STATUS)//data packet need link id
				{
					board = buff[OFF_BOARD];
					channel = buff[OFF_CHANNEL];
					buff[OFF_LINK_HIGH] = (links[board][channel].link >> 8) & 0xFF;
					buff[OFF_LINK_LOW] = links[board][channel].link & 0xFF;
				}
			}
			
			break;
		}
		index = (index + 1) % MAX_BOARD_NUM;
	}while( index < MAX_BOARD_NUM );

	return ret;
}

int transmit(unsigned int * buff, const int size)
{
	int ret = -ENOTRANSMIT;
	
	return ret;
}

int open_board(void)
{
	unsigned char board;

	for(board = 0; board < MAX_BOARD_NUM; board++)
	{
		if(is_board_configured(board))
			open_one_board(board);
	}
	
	if(!is_any_board_opened())
		return -ENODEVICE;

	return 0;
}
void open_one_board(unsigned char board)
{
	int fd;

	if((fd = open(dev[board][0], O_RDWR|O_NDELAY)) > 0)
	{
		boards[board].pci = fd;
		if((fd = open(dev[board][1], O_RDWR|O_NDELAY)) > 0)
		{
			boards[board].local = fd;
			boards[board].active = 1;
			sprintf(log_msg, "board %d is opended.", board);
			write_log(log_msg, DEBU);
		}
		else
		{
			close(boards[board].pci);
			sprintf(log_msg, "board %d is cann't be opened.", board);
			write_log(log_msg, DEBU);
		}
	}	
}
unsigned char is_any_board_opened(void)
{
	unsigned char board;
	unsigned char ret;
	ret = 0;
	for(board = 0; board < MAX_BOARD_NUM; board++)
	{
		if(is_one_board_opened(board))
		{
			ret = 1;
			break;
		}
	}

	return ret;
}

unsigned char is_one_board_opened(unsigned char board)
{
	return boards[board].active;
}
void init_board(void)
{
	 unsigned char board;
	 for(board = 0; board < MAX_BOARD_NUM; board++)
		 init_one_board(board);
}
void init_one_board(unsigned char board)
{
	if(is_one_board_opened(board))
	{	
		init_ds31256(board);		
		init_ds26519(board);
		sprintf(log_msg, "initialized board %d", board);
		write_log(log_msg, DEBU);
	}
}

void close_board(void)
{
	unsigned char board;
	for(board = 0; board < MAX_BOARD_NUM; board++)
		close_one_board(board);
}
void close_one_board(unsigned char board)
{	
	if(is_one_board_opened(board))
	{
		if(boards[board].pci > 0)
			close(boards[board].pci);
		if(boards[board].local > 0)
			close(boards[board].local);
		boards[board].active = 0;
		boards[board].pci = 0;
		boards[board].local = 0;
		sprintf(log_msg, "closed board %d", board);
		write_log(log_msg, DEBU);
	}
}
void start_board(void)
{
	unsigned char board;

	for(board = 0; board < MAX_BOARD_NUM; board++)
		start_one_board(board);
	
	running = 1;
}
void start_one_board(unsigned char board)
{
	if(is_one_board_opened(board))
	{
		start_ds31256(board);
		start_ds26519(board);
		sprintf(log_msg, "started board %d", board);
		write_log(log_msg, DEBU);
	}
}
void stop_board()
{
	unsigned char board;
	for(board = 0; board < MAX_BOARD_NUM; board++)
		stop_one_board(board);

	running = 0;
}
void stop_one_board(unsigned char board)
{
	if(is_one_board_opened(board))
	{
		stop_ds26519(board);
		stop_ds31256(board);
		sprintf(log_msg, "stopped board %d", board);
		write_log(log_msg, DEBU);
	}
}
void stop(void)
{
	if(is_running())
	{
		write_log("begin to stop hardware ...", INFO);
		stop_board();
		write_log("begin to close hardware ...", INFO);
		close_board();
		write_log("stop successfully", INFO);
	}
}

unsigned char is_running(void)
{
	return running;
}
unsigned char is_initialized(void)
{
	return initialized;
}
void init_ds31256(unsigned char board)
{ 
	if(is_one_board_opened(board))
	{
		write_log("begin to initialize GCR of DS31256 ...", DEBU);
		init_local(boards[board].pci);
		reset_ds31256(boards[board].pci);		
		write_log("begin to zero all indirect access RAMs of DS31256 ...", DEBU);
		zero_reg_ram(boards[board].pci);
		reset_ds31256(boards[board].pci);
		write_log("begin to initialize Layer1 Registers of DS31256 ...", DEBU);
		init_layer1(board);
		write_log("begin to initialize HDLC Registers of DS31256 ...", DEBU);
		init_hdlc(board);
		write_log("begin to initialize FIFO Registers of DS31256 ...", DEBU);
		init_fifo(board);
		write_log("begin to initizlize DMA Registers of DS31256 ...", DEBU);
		init_dma(board);
	}
}
void init_local(int fd)
{
	write_log("set local bus for bridge function", DEBU);
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_GCR_LBBMC, 0x0040));
	write_log("mask SDMA's interrupt", DEBU);
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_GCR_ISDMA, 0x0000));
}
void reset_ds31256(int fd)
{
	int cnt;
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_GCR_MRID, 1));
	for(cnt = 0; cnt < 100; cnt++)
		usleep(500);//wait 50 milseconds for all register initialized
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_GCR_MRID, 0));
}
void zero_reg_ram(int fd)
{
	int port,ts,channel;

	write_log("begin to zero Rx & Tx configuration RAM's for all ports ...", DEBU);
	for(port = 0; port < MAX_PORT_NUM; port++)
	{
		sprintf(log_msg, "begin to zero Rx & Tx configuration RAM's for port %d", port);
		write_log(log_msg, DEBU);
		ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_CPR_CP0RD + 8 * port, 0));
		for(ts = 0; ts < MAX_TS_NUM; ts++)
		{
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * port, 0x100 + ts));
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * port, 0x200 + ts));
		}
	}
	
	write_log("begin to zero all Rx & Tx indirect access registers' RAMs ...", DEBU);
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_HDLC_RHCD, 0));
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_HDLC_THCD, 0));
	ioctl(fd,NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_RFSBP, 0));
	ioctl(fd,NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_TFSBP, 0));
	ioctl(fd,NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_RFBP, 0));
	ioctl(fd,NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_TFBP, 0));
	ioctl(fd,NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_RFHWM, 0));
	ioctl(fd,NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_TFLWM, 0));
	ioctl(fd,NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_RDMA_RDMAC, 0));
	ioctl(fd,NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_TDMA_TDMAC, 0));
	for(channel = 0; channel < MAX_CHANNEL_NUM; channel++)
	{
		ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_HDLC_RHCDIS, channel));
		ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_HDLC_THCDIS, channel));
	
		ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_RFBPIS, channel));
		ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_TFBPIS, channel));

		ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_RFBPIS, channel));
		ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_TFBPIS, channel));
	
		ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_RFHWMIS, channel));
		ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_TFLWMIS, channel));
	
		ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_RDMA_RDMACIS, 0x400 + channel));
		ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_TDMA_TDMACIS, 0x200 + channel));
	}
}
void init_layer1(unsigned char board)
{
	unsigned char port;

	for(port = 0; port < MAX_PORT_NUM; port++)
	{
		if(is_port_configured(board, port))
		{
			sprintf(log_msg, "set port type for port %d of board %d", port, board);
			write_log(log_msg, DEBU);
			set_port_type(boards[board].pci, port, ports[board][port].port_mode);
			sprintf(log_msg, "allocate port timeslot for port %d of board %d", port, board);
			write_log(log_msg, DEBU);
			set_port_ts(board, port);
		}
	}
}
void set_port_type(int fd, unsigned char port, unsigned char port_mode)
{
	ioctl(fd,NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_RPR_RP0CR + 4 * port, port_mode << 6));
	ioctl(fd,NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_TPR_TP0CR + 4 * port, port_mode << 6));
}
void set_port_ts(unsigned char board, unsigned char port)
{		
	unsigned char start_ts, ts_num,ts;
	unsigned short channel;

	for(channel = 0; channel < MAX_CHANNEL_NUM; channel++)
	{			
		if(links[board][channel].port == port && links[board][channel].active)
		{
			start_ts = links[board][channel].start_ts;
			ts_num = links[board][channel].ts_num;

			ioctl(boards[board].pci, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_CPR_CP0RD + 8 * port, 0x00));
			for(ts = start_ts; ts < start_ts + ts_num; ts++)
				ioctl(boards[board].pci, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * port, ts));//zero Rx&Tx DS0 Data

			ioctl(boards[board].pci, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_CPR_CP0RD + 8 * port, channel));//allocate DS0 ts
			for(ts = start_ts; ts < start_ts + ts_num; ts++)
			{
				ioctl(boards[board].pci, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * port, 0x100 + ts));//Rx CFG                                           
				ioctl(boards[board].pci, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * port, 0x200 + ts));//Tx CFG
			}
		}	
	}
}
void init_hdlc(unsigned char board)
{
	unsigned short channel;

	for(channel = 0; channel < MAX_CHANNEL_NUM; channel++)
	{
		if(links[board][channel].active)
		{
			sprintf(log_msg, "set HDCL 16bit CRC mode for channel %d", channel);
			write_log(log_msg, DEBU);
			set_hdlc_crc_mode(boards[board].pci, channel);
		}
	}
}
void set_hdlc_crc_mode(int fd, unsigned char channel)
{
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_HDLC_RHCD, 0x00|(CRC_MODE << 2)));
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_HDLC_THCD, 0x100|(CRC_MODE << 2)));//16bit CRC
	ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_HDLC_RHCDIS, channel));
	ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_HDLC_THCDIS, channel));
}
void init_fifo(unsigned char board)
{
	int fd,block, block_num;
	unsigned short channel;

	block_num = BLOCKS_PER_CHANNEL;
	fd = boards[board].pci;
	for(channel = 0; channel < MAX_CHANNEL_NUM; channel++)
	{
		if(links[board][channel].active)
		{
			sprintf(log_msg, "build Tx & Rx FIFO block linked list for channel %d", channel);
			write_log(log_msg, DEBU);
			for(block = channel * block_num; block < (channel + 1) * block_num; block++)
			{
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_RFBP, block + 1));
				ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_RFBPIS, block));
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_TFBP, block + 1));
				ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_TFBPIS, block));
			}
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_RFBP, channel * block_num));
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_RFBPIS, (channel + 1) * block_num - 1));
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_TFBP, channel * block_num));
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_TFBPIS, (channel + 1) * block_num - 1));

			sprintf(log_msg, "assign the start block of circular linked list to the HDLC channel for channel %d", channel);
			write_log(log_msg, DEBU);
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_RFSBP, channel * block_num));
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_RFSBPIS, channel));
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_TFSBP, channel * block_num));
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_TFSBPIS, channel));

			sprintf(log_msg, "set Rx high watermark and Tx low watermark for channel %d", channel);
			write_log(log_msg, DEBU);
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_RFHWM, block_num - 1));
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_RFHWMIS, channel));
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_FIFO_TFLWM, 1));
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_FIFO_TFLWMIS, channel));
		}
	}
}
void init_dma(unsigned char board)
{
	unsigned short channel;
	int fd;

	fd = boards[board].pci;

	write_log("configure all DMA Registers", DEBU);
	ioctl(fd, NV_IOC_CONFIGDMA, 0);
    
	for(channel = 0; channel < MAX_CHANNEL_NUM; channel++)
	{
		if(links[board][channel].active)
		{		
			// Set bit 0 = 0 to disable the HDLC Channel
			// Set bit 2-1 = 00 for large buffers only
			// Set bit 6-3 = 0000 for 0 byte offset from the data buffer address of the first data buffer
			// Set Bit 9-7 = 000 for DMA write to the Done Queue only after packet reception is complete
			// Set the HDLC Channel Number by RDMACIS register
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_RDMA_RDMAC, 0x00));
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_RDMA_RDMACIS, 0x400 + channel));
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_TDMA_TDMAC, 0x02));
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_TDMA_TDMACIS, 0x200 + channel));
			//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_RDMA_RDMAQ, 0x11));
		}
	}
}
void start_ds31256(unsigned char board)
{
	unsigned char ds,port;
	unsigned short channel;
	int fd;
	unsigned int data;//high word = reg address, low word = reg value
	fd = boards[board].pci;

	write_log("enable interrupt for SDMA", DEBU);
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_GCR_ISDMA, 0x0C20));
	
	write_log("enable the DMAs in MC", DEBU);
	// Set bit 0 = 1 to enable Receive DMA
	// Set bits 2-1 = 00 to burst length maximum is 32 dwords
	// Set bit 3 = 0 to enable Transmit DMA
	// Set bits 6 = 0 for HDLC packet data on PCI bus is little endian
	// Set bits 11-7 = 00000 to select Port 0 has the dedicated resources of the BERT
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_GCR_MC, 0x0001));

	write_log("enable the HDLC channels in R[n]CFG[j] and T[n]CFG[j] registers", DEBU);
	for(channel = 0; channel < MAX_CHANNEL_NUM; channel++)
	{
		if(links[board][channel].active)
		{
			sprintf(log_msg, "enable the Port RAMs for each DS0 of HDLC channel %d in Channelized Port Register Data Register(Rx&Tx)", channel);
			write_log(log_msg, DEBU);
			for(ds = links[board][channel].start_ts; ds < links[board][channel].start_ts + links[board][channel].ts_num; ds++)
			{
				//Rx
				ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * links[board][channel].port, 0x4100 + ds));
				data = ioctl(fd, NV_IOC_READ_REG,MK_ADD_VAL(DS31256_CPR_CP0RD + 8 * links[board][channel].port, 0));
				ioctl(fd, NV_IOC_WRITE_REG, data | 0x8000);//enable Rx DS0
				ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * links[board][channel].port, 0x0100 + ds));
				//Tx
				ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * links[board][channel].port, 0x4200 + ds));
				data = ioctl(fd, NV_IOC_READ_REG,MK_ADD_VAL(DS31256_CPR_CP0RD + 8 * links[board][channel].port, 0));
				ioctl(fd, NV_IOC_WRITE_REG, data | 0x8000);//enable Tx DS0
				ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * links[board][channel].port, 0x0200 + ds));
			}
			sprintf(log_msg, "enable the DMA Control Register of HDLC channel %d in DMA Configuration RAM(Rx&Tx)", channel);
			write_log(log_msg, DEBU);
			//Rx
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_RDMA_RDMACIS, 0x4400 + channel));
			data = ioctl(fd, NV_IOC_READ_REG, MK_ADD_VAL(DS31256_RDMA_RDMAC, 0));
			ioctl(fd, NV_IOC_WRITE_REG, data | 0x0001);
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_RDMA_RDMACIS, 0x0400 + channel));
			//Tx
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_TDMA_TDMACIS, 0x4200 + channel));
			data = ioctl(fd, NV_IOC_READ_REG, MK_ADD_VAL(DS31256_TDMA_TDMAC, 0));
			ioctl(fd, NV_IOC_WRITE_REG, data | 0x0001);
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_TDMA_TDMACIS, 0x0200 + channel));
		}		
	}

	write_log("allow port data to be transmitted normally", DEBU);
	for(port = 0; port < MAX_PORT_NUM; port++)
	{
		if(ports[board][port].active)
		{				
			data = ioctl(fd, NV_IOC_READ_REG, MK_ADD_VAL(DS31256_TPR_TP0CR + 4 * port, 0));
			ioctl(fd, NV_IOC_WRITE_REG, data | 0x0008);
			sprintf(log_msg, "start port %d to transmint data", port);
			write_log(log_msg, DEBU);
		}
	}

}
void start_ds26519(unsigned char board)
{
	int port,offset,fd;

	fd = boards[board].local;
	
	for(port = 0; port < MAX_PORT_NUM; port++)
	{
		if(ports[board][port].active)
		{
			offset = 0x200 * (port % 8) + 0x2000 * (port / 8);
			sprintf(log_msg, "Transimitter of framer %d powered down", port);
			write_log(log_msg, DEBU);
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_LIU_LMCR + offset, 0x00));

			sprintf(log_msg, "enable interrupt by setting RIM1 register for framer %d", port);
			write_log(log_msg, DEBU);
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_RIM1 + offset, 0xFF));

			sprintf(log_msg, "set INIT_DONE bit to make framer %d to begin operation based on the initial configuration", port);
			write_log(log_msg, DEBU);
			if(ports[board][port].port_type == PORT_TYPE_E1)
			{
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_RMMR + offset, 0xC1));
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_TMMR + offset, 0xC1));
			}
			else
			{
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_RMMR + offset, 0xC0));
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_TMMR + offset, 0xC0));
			}
		}
	}
}
void stop_ds31256(int board)
{
	unsigned char ds,port;
	unsigned short channel;

	int fd;
	unsigned int data;//high word = reg address, low word = reg value
	fd = boards[board].pci;
	
	// Set bit 0 = 0 to disable Receive DMA
	// Set bits 2-1 = 00 to burst length maximum is 32 dwords
	// Set bit 3 = 0 to enable Transmit DMA
	// Set bits 6 = 0 for HDLC packet data on PCI bus is little endian
	// Set bits 11-7 = 00000 to select Port 0 has the dedicated resources of the BERT
	sprintf(log_msg, "begin to disable the DS31256 of board %d", board); 
	write_log(log_msg, DEBU);
	write_log("disable the DMAs in MC", DEBU);
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_GCR_MC, 0x0000));

	write_log("disable the HDLC channels in R[n]CFG[j] and T[n]CFG[j] registers", DEBU);
	for(channel = 0; channel < MAX_CHANNEL_NUM; channel++)
	{
		if(links[board][channel].active)
		{
			sprintf(log_msg, "disable the Port RAMs for each DS0 of HDLC channel %d in Channelized Port Register Data Register(Rx&Tx)", channel);
			write_log(log_msg, DEBU);
			for(ds = links[board][channel].start_ts; ds < links[board][channel].start_ts + links[board][channel].ts_num; ds++)
			{
				//Rx
				ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * links[board][channel].port, 0x4100 + ds));
				data = ioctl(fd, NV_IOC_READ_REG,MK_ADD_VAL(DS31256_CPR_CP0RD + 8 * links[board][channel].port, 0));
				ioctl(fd, NV_IOC_WRITE_REG, data & 0x7FFF);//disable Rx DS0
				ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * links[board][channel].port, 0x0100 + ds));
				//Tx
				ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * links[board][channel].port, 0x4200 + ds));
				data = ioctl(fd, NV_IOC_READ_REG,MK_ADD_VAL(DS31256_CPR_CP0RD + 8 * links[board][channel].port, 0));
				ioctl(fd, NV_IOC_WRITE_REG, data & 0x7FFF);//disable Tx DS0
				ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_CPR_CP0RDIS + 8 * links[board][channel].port, 0x0200 + ds));
			}
			sprintf(log_msg, "disable the DMA Control Register of HDLC channel %d in DMA Configuration RAM(Rx&Tx)", channel);
			write_log(log_msg, DEBU);
			//Rx
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_RDMA_RDMACIS, 0x4400 + channel));
			data = ioctl(fd, NV_IOC_READ_REG, MK_ADD_VAL(DS31256_RDMA_RDMAC, 0));
			ioctl(fd, NV_IOC_WRITE_REG, data & 0xFFFE);
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_RDMA_RDMACIS, 0x0400 + channel));
			//Tx
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_TDMA_TDMACIS, 0x4200 + channel));
			data = ioctl(fd, NV_IOC_READ_REG, MK_ADD_VAL(DS31256_TDMA_TDMAC, 0));
			ioctl(fd, NV_IOC_WRITE_REG, data & 0xFFFE);
			ioctl(fd, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(DS31256_TDMA_TDMACIS, 0x0200 + channel));
		}		
	}

	write_log("begin to stop port data to be transmitted normally...", DEBU);
	for(port = 0; port < MAX_PORT_NUM; port++)
	{
		if(ports[board][port].active)
		{			
			
			data = ioctl(fd, NV_IOC_READ_REG, MK_ADD_VAL(DS31256_TPR_TP0CR + 4 * port, 0));
			ioctl(fd, NV_IOC_WRITE_REG, data | 0xFFF7);
			sprintf(log_msg, "stopped port %d to transmint data", port);
			write_log(log_msg, DEBU);
		}
	}
	
	write_log("disable the interrupt", DEBU);
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS31256_GCR_ISDMA, 0x0000));//disable interrupt;
	write_log("reset all registers of DS31256", DEBU);
	reset_ds31256(fd);
}
void stop_ds26519(int board)
{
	int port,offset,fd;

	fd = boards[board].local;
	
	for(port = 0; port < MAX_PORT_NUM; port++)
	{
		if(ports[board][port].active)
		{
			offset = 0x200 * (port % 8) + 0x2000 * (port / 8);

			sprintf(log_msg, "disable framer %d of DS26519", port);
			write_log(log_msg, DEBU);			
			if(ports[board][port].port_type == PORT_TYPE_E1)
			{
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_RMMR + offset, 0x01));
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_TMMR + offset, 0x01));
			}
			else
			{
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_RMMR + offset, 0x00));
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_TMMR + offset, 0x00));
			}

			sprintf(log_msg, "Receiver & Transimitter of framer %d powered down", port);
			write_log(log_msg, DEBU);
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_LIU_LMCR + offset, 0x06));

			sprintf(log_msg, "Disable interrupt by setting RIM1 register for framer %d", port); 
			write_log(log_msg, DEBU);
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_RIM1 + offset, 0x00));
		}
	}
	write_log("reset all registers of DS26519", DEBU);	
	reset_ds26519(fd);
}
int init_ds26519(unsigned char board)
{
	write_log("reset DS26519", DEBU);	
	reset_ds26519(boards[board].local);
	write_log("initialize global registers for DS26519", DEBU);
	init_global(boards[board].local);
	write_log("initialize framer registers for DS26519", DEBU);
	init_framer(board);
	write_log("initialize LIU registers for DS26519", DEBU);
	init_liu(board);
	write_log("initialize BERT registers for DS26519", DEBU);
	init_bert();
}

void reset_ds26519(int fd)
{
	int reg;
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GSRR1, 0x07));
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GSRR2, 0x07));
	usleep(500);//wait for all registers init
	for(reg = 0; reg < 0x4000; reg++)
	{
		ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(reg, 0x00));//zero all register
		usleep(5);
	}
}
void init_global(int fd)
{
	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GTCR1, 0x00));
	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GTCR2, 0x00));
	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GTCR3, 0x00));
	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GTCR4, 0x00));

	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GFCR1, 0x00));
	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GFCR2, 0x00));

	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GTCCR1, 0x80));
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GTCCR2, 0x80));
	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GTCCR3, 0x00));
	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GTCCR4, 0x00));

	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GFIMR1, 0xff));//enable framer interrupt
	ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GFIMR2, 0xff));

	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GBIMR1, 0xff));//enable BERT interrupt
	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GBIMR2, 0xff));

	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GLIMR1, 0xff));//enable LIU interrupt
	//ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_GR_GLIMR2, 0xff));
}

void init_framer(unsigned char board)
{
	int port,offset,fd;

	fd = boards[board].local;
	for(port = 0; port < MAX_PORT_NUM; port++)
	{
		if(ports[board][port].active)
		{
			offset = 0x200 * (port % 8) + 0x2000 * (port / 8);
			
			if(ports[board][port].port_type == PORT_TYPE_E1)
			{
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_RMMR + offset, 0x81));
			    ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_TMMR + offset, 0x81));
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_RCR1 + offset, 0x20 | ports[board][port].code_type << 6 | ports[board][port].frame_type << 3));
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_TCR1 + offset, 0x80 | ports[board][port].code_type << 2 | ports[board][port].frame_type));
			}
			else
			{
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_RMMR + offset, 0x80));
			    ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_TMMR + offset, 0x80));
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_RCR1 + offset, ports[board][port].code_type << 6 | ports[board][port].frame_type << 5));
				ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_FRAMER_TCR1 + offset, ports[board][port].code_type << 2));
			}
		}
	}
}

void init_liu(unsigned char board)
{
	int port, offset, fd;
	fd = boards[board].local;

	for(port = 0; port < MAX_PORT_NUM; port++)
	{
		if(ports[board][port].active)
		{
			offset = 0x20 * (port % 8) + 0x2000 * (port / 8);
			//bit 7 = 1 RTIPn and RTIPEn are connected
			//bit 6 = 1 Receive internal impedance termination is enabled
			//bit 2-0 = 000 port impedance is 75 ohm
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_LIU_LRISMR + offset, 0xC0 | ports[board][port].impedance));
			//bit 6 = 0 Normal operation using software for hitless protection
			//        = 1 Hitless protection switching mode using TXENABLE pin.
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_LIU_LTRCR + offset, ports[board][port].port_type << 1));
			//bit 0 = 0 TTIPn/TRINGn outputs are high impedance.
			//bit 1 = 1 Receiver powered down.
			//bit 2 = 1 Transmitter powered down. 
			//bit 5-3 = 100 Local loopback
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_LIU_LMCR + offset, 0x04));
			//bit 1-0 = 00 Max 12dB cable loss allowed for E1
			ioctl(fd, NV_IOC_WRITE_REG, MK_ADD_VAL(DS26519_LIU_LRCR + offset, 0x00));
		}
	}
}
void init_bert(void)
{}
void set_dump_option(char dump_option)
{
	dump_regs_option = dump_option;
}
void write_log(char * msg, unsigned char level)
{
	time_t now; 
	//struct timeval now;
	int len,index = 0;
	
	char strTime[20] = {0}; 
	//char buffer[255] = {0};
	FILE * filp;
	if(msg == NULL)
		return;
	if(level > log_level)
		return;

	len = strlen(msg);
	while(index < len)
	{
		if(isgraph(msg[index++]))
			break;
	}
	if(index == len)
		return;

	time(&now);   
	strftime(strTime,   sizeof(strTime),   "%Y%m%d-%H:%M:%S",   localtime(&now));
	/*gettimeofday(&now, NULL);
	sprintf(strTime, "%d.%06d", (int)now.tv_sec, (int)now.tv_usec);*/
	pthread_mutex_lock(&nv_mutex);
	filp = fopen(log_file, "aw");

	if(filp != NULL)
	{
		fprintf(filp, "[%s][%s]-%s\n", strTime, log_flag[level], msg);
		fclose(filp);
	}
	else
		printf("can't write log msg %s\n", msg);
	pthread_mutex_unlock(&nv_mutex);

}
void set_logfile_name(char * filename)
{
	if(filename != NULL)
		log_file = filename;
}
void set_log_level(const unsigned char level)
{
	log_level = level & 0xFF;
}
void dump_regs (char *filename, char dev)
{
	FILE *fptr;

	if(boards[dev].active)
	{
		/* Open specified file for register dump */
		fptr = fopen (filename, "aw");
		
		if (fptr == NULL)
		{
			write_log("Can't open the file", ERRO);
			return;
		}
		if(dump_regs_option & DUMP_REG_DS31256)
			dump_ds31256(fptr, dev);
		if(dump_regs_option & DUMP_REG_DS26519)
			dump_ds26519(fptr, dev);

		fclose(fptr);
	}
	else
		write_log("board 0 is unactive.", INFO);
}
void dump_ds31256(FILE * fptr, char dev)
{
	int addr, i, port;
	if(!boards[dev].active)
	{
		fprintf(fptr, "Device %d is not active, DS31256 will not dump.\n", dev);
		return;
	}
	logger = boards[dev].pci;
	/* Dump the contents of registers by category to the specified file */
	fprintf (fptr, " Dump of DS31256 Registers(Device %d)\n\n", dev);
	fprintf (fptr, " General Config Registers\n");
	fprintf (fptr, "MRID:\t %.4x\n", read_reg(0x0));
	fprintf (fptr, "MC: \t %.4x\n", read_reg(0x10));
	fprintf (fptr, "SM: \t %.4x\n", read_reg(0x20));
	fprintf (fptr, "ISM: \t %.4x\n", read_reg(0x24));
	fprintf (fptr, "SDMA: \t %.4x\n" , read_reg(0x28));
	fprintf (fptr, "ISDMA: \t %.4x\n ", read_reg(0x2C));
	fprintf (fptr,"SV54:\t %.4x\n", read_reg(0x30));
	fprintf (fptr,"ISV54: \t %.4x\n", read_reg(0x34));
	fprintf (fptr,"LBBMC: \t %.4x\n ", read_reg(0x40));
	fprintf (fptr,"TEST: \t %.4x\n", read_reg(0x50));
	fprintf (fptr,"Receive Port Registers \n");
	for (i = 0, addr = 0x100; addr <= 0x13c; addr += 4, i++)
	{
		fprintf (fptr,"RP%dCR: %.4x\t", i, read_reg(addr));
		if ((i & 3) == 3)
			fprintf (fptr, "\n");
	}
	fprintf (fptr, "Transmit Port Registers\n");
	for (i = 0, addr = 0x200; addr <= 0x23c; addr += 4, i++)
	{
		fprintf (fptr,"TP%dCR:%.4x\t", i , read_reg( addr));
		if ((i & 3) == 3)
			fprintf (fptr, "\n");
	}
	for (port = 0, addr = 0x300; port < 16; port++, addr += 8)
	{
		fprintf (fptr, "Channelized Port Registers, Port %d \n", port);
		for (i = 0; i < 32; i++)
		{
			fprintf (fptr,"C%dDAT%d : %.4x\t", port, i , read_ind_reg(addr, i));
			fprintf (fptr, "R%dCFG%d :  %.4x\t", port, i ,read_ind_reg(addr, i | 0x100));
			fprintf (fptr, "T%dCFG%d:  %.4x\n", port, i, read_ind_reg(addr, i | 0x200));
		}

		fprintf (fptr, "HDLC Registers \n");
		fprintf (fptr, "RHPL:  %.4x\n", read_reg(0x410));
		for (i = 0; i < 20; i++)
		{
			fprintf (fptr,"RHCD%d :  %.4x\t", i, read_ind_reg (0x400, i));
			fprintf (fptr,"THCD%d : %.4x\n", i, read_ind_reg (0x480, i));
		}
	}
	fprintf (fptr, "BERT Registers\n");
	fprintf (fptr, "BERTC0 :  %.4x\t", read_reg(0x500));
	fprintf (fptr, "BERTC1 :  %.4x\t", read_reg(0x504));
	fprintf (fptr, "BERTRP0 :  %.4x\t", read_reg(0x508));
	fprintf (fptr, "BERTRP1 :  %.4x \n", read_reg(0x50c));
	fprintf (fptr,"BERTBC0 :  %.4x \t", read_reg(0x510));
	fprintf (fptr,"BERTBC1 :  %.4x \t", read_reg(0x514));
	fprintf (fptr,"BERTEC0 :  %.4x \t", read_reg(0x518));
	fprintf (fptr,"BERTEC1 :  %.4x \n", read_reg(0x51c));
	fprintf (fptr,"Receive DMA Registers \n");
	fprintf (fptr,"RFQBA0 :  %.4x\t", read_reg(0x700));
	fprintf (fptr,"RFQBA1 :  %.4x\t", read_reg(0x704));
	fprintf (fptr,"RFQEA :  %.4x\n", read_reg(0x708));
	fprintf (fptr,"RFQSBSA :  %.4x \t", read_reg(0x70c));
	fprintf (fptr,"RFQLBWP :  %.4x\t", read_reg(0x710));
	fprintf (fptr,"RFQSBWP :  %.4x\t", read_reg(0x714));
	fprintf (fptr,"RFQLBRP :  %.4x\t", read_reg(0x718));
	fprintf (fptr,"RFQSBRP :  %.4x\n", read_reg(0x71c));
	fprintf (fptr,"RDQBA0 :  %.4x\t", read_reg(0x730));
	fprintf (fptr,"RDQBA1 :  %.4x\t", read_reg(0x734));
	fprintf (fptr,"RDQEA :  %.4x\n", read_reg(0x738));
	fprintf (fptr,"RDQRP :  %.4x \t", read_reg(0x73c));
	fprintf (fptr,"RDQWP :  %.4x\t", read_reg(0x740));
	fprintf (fptr,"RDQFFT :  %.4x\n", read_reg(0x744));
	fprintf (fptr,"RDBA0 :  %.4x\t", read_reg(0x750));
	fprintf (fptr,"RDBA1 :  %.4x \t", read_reg(0x754));
	fprintf (fptr,"RDMAQ :  %.4x\t", read_reg(0x780));
	fprintf (fptr,"RLBS :  %.4x\t", read_reg(0x790));
	fprintf (fptr,"RSBS : %.4x\n", read_reg(0x794));
	fprintf (fptr,"Receive DMA Channel Configuration \n");
	for (i = 0; i < 20; i++)
	{
		fprintf (fptr,"Channel %d : \t ", i);
		fprintf (fptr, "%.4x\t", read_ind_reg (0x770, 0x100 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg (0x770, 0x000 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg (0x770, 0x300 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg (0x770, 0x200 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg (0x770, 0x500 + i));
		fprintf (fptr, "%.4x\n", read_ind_reg ( 0x770, 0x400 + i));
	}
	fprintf (fptr, "Transmit DMA Registers \n");
	fprintf (fptr, "TPQBA0 :  %.4x\t", read_reg(0x800));
	fprintf (fptr, "TPQBA1 :  %.4x\t", read_reg(0x804));
	fprintf (fptr, "TPQEA :  %.4x\t", read_reg(0x808));
	fprintf (fptr, "TPQWP :  %.4x\t", read_reg(0x80c));
	fprintf (fptr, "TPQRP :  %.4x\n", read_reg(0x810));
	fprintf (fptr, "TDQBA0 :  %.4x\t", read_reg(0x830));
	fprintf (fptr, "TDQBA1 :  %.4x\t", read_reg(0x834));
	fprintf (fptr, "TDQEA :  %.4x\t", read_reg(0x838));
	fprintf (fptr, "TDQWP :  %.4x\t", read_reg(0x83c));
	fprintf (fptr, "TDQRP :  %.4x\n", read_reg(0x840));
	fprintf (fptr,"TDQFFT :  %.4x\t", read_reg(0x844));
	fprintf (fptr,"TDBA0 :  %.4x\t", read_reg(0x850));
	fprintf (fptr, "TDBA1 :  %.4x\t", read_reg(0x854));
	fprintf (fptr, "TDMAQ : %.4x\n", read_reg(0x880));
	fprintf (fptr, "Transmit DMA Channel Configuration \n");
	for (i = 0; i < 20; i++)
	{
		fprintf (fptr, "Channel %d : \t", i);
		fprintf (fptr, "%.4x\t", read_ind_reg(0x870, 0x100 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg(0x870, 0x000 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg(0x870, 0x300 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg(0x870, 0x200 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg(0x870, 0x500 + i));
		fprintf (fptr, "%.4x\n", read_ind_reg(0x870, 0x400 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg(0x870, 0x700 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg(0x870, 0x600 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg(0x870, 0x900 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg(0x870, 0x800 + i));
		fprintf (fptr, "%.4x\t", read_ind_reg(0x870, 0xb00 + i));
		fprintf (fptr, "%.4x\n", read_ind_reg(0x870, 0xa00 + i));
	}
}
void dump_ds26519(FILE * fptr, char dev)
{
	unsigned int offset, port;
	if(!boards[dev].active)
	{
		fprintf(fptr, "Device %d is not active, DS26519 will not dump.\n", dev);
		return;
	}
	logger = boards[dev].local;
	fprintf (fptr, " \n\nDump of DS26519 Registers(Device %d)\n\n", dev);
	fprintf(fptr, "Global Register\n");
	fprintf(fptr, "GTCR1:%02X, GTCR2:%02X, GTCR3:%02X, GTCR4:%02X\n", read_reg8(DS26519_GR_GTCR1), read_reg8(DS26519_GR_GTCR2), read_reg8(DS26519_GR_GTCR3), read_reg8(DS26519_GR_GTCR4));
	fprintf(fptr, "GFCR1:%02X, GFCR2:%02X\n", read_reg8(DS26519_GR_GFCR1), read_reg8(DS26519_GR_GFCR2));
	fprintf(fptr, "GTCCR1:%02X, GTCCR2:%02X, GTCCR3:%02X, GTCCR4:%02X\n", read_reg8(DS26519_GR_GTCCR1), read_reg8(DS26519_GR_GTCCR2), read_reg8(DS26519_GR_GTCCR3), read_reg8(DS26519_GR_GTCCR4));
	fprintf(fptr, "GSRR1:%02X, GSRR2:%02X\n", read_reg8(DS26519_GR_GSRR1), read_reg8(DS26519_GR_GSRR2));
	fprintf(fptr, "IDR:%02X\n", read_reg8(DS26519_GR_IDR));
	fprintf(fptr, "GFISR1:%02X, GFISR2:%02X\n", read_reg8(DS26519_GR_GFISR1), read_reg8(DS26519_GR_GFISR2));
	fprintf(fptr, "GBISR1:%02X, GBISR2:%02X\n", read_reg8(DS26519_GR_GBISR1), read_reg8(DS26519_GR_GBISR2));
	fprintf(fptr, "GLISR1:%02X, GLISR2:%02X\n", read_reg8(DS26519_GR_GLISR1), read_reg8(DS26519_GR_GLISR2));
	fprintf(fptr, "GFIMR1:%02X, GFIMR2:%02X\n", read_reg8(DS26519_GR_GFIMR1), read_reg8(DS26519_GR_GFIMR2));
	fprintf(fptr, "GBIMR1:%02X, GBIMR2:%02X\n", read_reg8(DS26519_GR_GBIMR1), read_reg8(DS26519_GR_GBIMR2));
	fprintf(fptr, "GLIMR1:%02X, GLIMR2:%02X\n", read_reg8(DS26519_GR_GLIMR1), read_reg8(DS26519_GR_GLIMR2));


	for(port = 0; port < 16; port++)
	{
		offset = (port % 8) * 0x20 + 0x2000 * ( port / 8);
		fprintf(fptr, "Port %d LIU Register:\t", port + 1);
		fprintf(fptr, "LTRCR:%02x\t",  read_reg8(DS26519_LIU_LTRCR + offset));
		fprintf(fptr, "LTIPSR:%02x\t",  read_reg8(DS26519_LIU_LTIPSR + offset));
		fprintf(fptr, "LMCR:%02x\t",  read_reg8(DS26519_LIU_LMCR + offset));
		fprintf(fptr, "LRSR:%02x\t",  read_reg8(DS26519_LIU_LRSR + offset));
		fprintf(fptr, "LSIMR:%02x\t",  read_reg8(DS26519_LIU_LSIMR + offset));
		fprintf(fptr, "LLSR:%02x\t",  read_reg8(DS26519_LIU_LLSR + offset));
		fprintf(fptr, "LRSL:%02x\t",  read_reg8(DS26519_LIU_LRSL + offset));
		fprintf(fptr, "LRISMR:%02x\t",  read_reg8(DS26519_LIU_LRISMR + offset));
		fprintf(fptr, "LRCR:%02x\n",  read_reg8(DS26519_LIU_LRCR + offset));
	}
	fprintf(fptr, "\n");
	for(port = 0; port < 16; port++)
	{
		offset = (port % 8) * 0x10 + 0x2000 * ( port / 8);
		fprintf(fptr, "Port %d BERT Register:\t", port + 1);
		fprintf(fptr, "BAWC:%02x\t",  read_reg8(DS26519_BERT_BAWC + offset));
		fprintf(fptr, "BRP1:%02x\t",  read_reg8(DS26519_BERT_BRP1 + offset));
		fprintf(fptr, "BRP2:%02x\t",  read_reg8(DS26519_BERT_BRP2 + offset));
		fprintf(fptr, "BRP3:%02x\t",  read_reg8(DS26519_BERT_BRP3 + offset));
		fprintf(fptr, "BRP4:%02x\t",  read_reg8(DS26519_BERT_BRP4 + offset));
		fprintf(fptr, "BC1:%02x\t",  read_reg8(DS26519_BERT_BC1 + offset));
		fprintf(fptr, "BC2:%02x\t",  read_reg8(DS26519_BERT_BC2 + offset));
		fprintf(fptr, "BBC1:%02x\t",  read_reg8(DS26519_BERT_BBC1 + offset));
		fprintf(fptr, "BBC2:%02x\t",  read_reg8(DS26519_BERT_BBC2 + offset));
		fprintf(fptr, "BBC3:%02x\t",  read_reg8(DS26519_BERT_BBC3 + offset));
		fprintf(fptr, "BBC4:%02x\t",  read_reg8(DS26519_BERT_BBC4 + offset));
		fprintf(fptr, "BEC1:%02x\t",  read_reg8(DS26519_BERT_BEC1 + offset));
		fprintf(fptr, "BEC2:%02x\t",  read_reg8(DS26519_BERT_BEC2 + offset));
		fprintf(fptr, "BEC3:%02x\t",  read_reg8(DS26519_BERT_BEC3 + offset));
		fprintf(fptr, "BSR:%02x\t",  read_reg8(DS26519_BERT_BSR + offset));
		fprintf(fptr, "BSIM:%02x\n",  read_reg8(DS26519_BERT_BSIM + offset));
	}
	fprintf(fptr, "\n");
	for(port = 0; port < 16; port++)
	{
		offset = (port % 8) * 0x200 + 0x2000 *(port / 8);
		fprintf(fptr, "Port %d Framer Register:\t", port + 1);
		fprintf(fptr, "RMMR:%02X\t", read_reg8(DS26519_FRAMER_RMMR + offset));
		fprintf(fptr, "E1RRTS7:%02X\t", read_reg8(DS26519_FRAMER_E1RRTS7 + offset));
		fprintf(fptr, "E1RRA:%02X\t", read_reg8(DS26519_FRAMER_E1RRA + offset));
		fprintf(fptr, "RLS1:%02X\t", read_reg8(DS26519_FRAMER_RLS1 + offset));
		fprintf(fptr, "RLS2:%02X\t", read_reg8(DS26519_FRAMER_RLS2 + offset));
		fprintf(fptr, "RLS3:%02X\t", read_reg8(DS26519_FRAMER_RLS3 + offset));
		fprintf(fptr, "RLS4:%02X\t", read_reg8(DS26519_FRAMER_RLS4 + offset));
		fprintf(fptr, "RLS5:%02X\t", read_reg8(DS26519_FRAMER_RLS5 + offset));
		fprintf(fptr, "RLS7:%02X\n", read_reg8(DS26519_FRAMER_RLS7 + offset));

		fprintf(fptr, "RSS1:%02X\t", read_reg8(DS26519_FRAMER_RSS1 + offset));
		fprintf(fptr, "RSS2:%02X\t", read_reg8(DS26519_FRAMER_RSS2 + offset));
		fprintf(fptr, "RSS3:%02X\t", read_reg8(DS26519_FRAMER_RSS3 + offset));
		fprintf(fptr, "RSS4:%02X\t", read_reg8(DS26519_FRAMER_RSS4 + offset));
		fprintf(fptr, "RRTS1:%02X\t", read_reg8(DS26519_FRAMER_RRTS1 + offset));
		fprintf(fptr, "RRTS3:%02X\t", read_reg8(DS26519_FRAMER_RRTS3 + offset));
		fprintf(fptr, "RRTS5:%02X\n", read_reg8(DS26519_FRAMER_RRTS5 + offset));

		fprintf(fptr, "E1RAF:%02X\t", read_reg8(DS26519_FRAMER_E1RAF + offset));
		fprintf(fptr, "E1RNAF:%02X\t", read_reg8(DS26519_FRAMER_E1RNAF + offset));
		fprintf(fptr, "E1RSiAF:%02X\t", read_reg8(DS26519_FRAMER_E1RSiAF + offset));
		fprintf(fptr, "E1RSiNAF:%02X\t", read_reg8(DS26519_FRAMER_E1RSiNAF + offset));
		fprintf(fptr, "E1RSa4:%02X\t", read_reg8(DS26519_FRAMER_E1RSa4 + offset));
		fprintf(fptr, "E1RSa5:%02X\t", read_reg8(DS26519_FRAMER_E1RSa5 + offset));
		fprintf(fptr, "E1RSa6:%02X\t", read_reg8(DS26519_FRAMER_E1RSa6 + offset));
		fprintf(fptr, "E1RSa7:%02X\t", read_reg8(DS26519_FRAMER_E1RSa7 + offset));
		fprintf(fptr, "E1RSa8:%02X\n", read_reg8(DS26519_FRAMER_E1RSa8 + offset));

		fprintf(fptr, "E1TAF:%02X\t", read_reg8(DS26519_FRAMER_E1TAF + offset));
		fprintf(fptr, "E1TNAF:%02X\t", read_reg8(DS26519_FRAMER_E1TNAF + offset));
		fprintf(fptr, "E1TSiAF:%02X\t", read_reg8(DS26519_FRAMER_E1TSiAF + offset));
		fprintf(fptr, "E1TSiNAF:%02X\t", read_reg8(DS26519_FRAMER_E1TSiNAF + offset));
		fprintf(fptr, "E1TSa4:%02X\t", read_reg8(DS26519_FRAMER_E1TSa4 + offset));
		fprintf(fptr, "E1TSa5:%02X\t", read_reg8(DS26519_FRAMER_E1TSa5 + offset));
		fprintf(fptr, "E1TSa6:%02X\t", read_reg8(DS26519_FRAMER_E1TSa6 + offset));
		fprintf(fptr, "E1TSa7:%02X\t", read_reg8(DS26519_FRAMER_E1TSa7 + offset));
		fprintf(fptr, "E1TSa8:%02X\t", read_reg8(DS26519_FRAMER_E1TSa8 + offset));
		fprintf(fptr, "E1TSACR:%02X\n", read_reg8(DS26519_FRAMER_E1TSACR + offset));

		fprintf(fptr, "TRTS2:%02X\t", read_reg8(DS26519_FRAMER_TRTS2 + offset));
		fprintf(fptr, "E1RRA:%02X\t", read_reg8(DS26519_FRAMER_E1TRA + offset));
		fprintf(fptr, "TLS1:%02X\t", read_reg8(DS26519_FRAMER_TLS1 + offset));
		fprintf(fptr, "TLS2:%02X\t", read_reg8(DS26519_FRAMER_TLS2 + offset));
		fprintf(fptr, "TLS3:%02X\n\n", read_reg8(DS26519_FRAMER_TLS3 + offset));

	}
}
unsigned short read_reg(const unsigned short addr)
{	
	return 0xFFFF & ioctl(logger, NV_IOC_READ_REG, MK_ADD_VAL(addr, 0));
}
unsigned short read_ind_reg(const unsigned short addr, const unsigned short index)
{	
	ioctl(logger, NV_IOC_WRITE_REG_IS, MK_ADD_VAL(addr, index | 0x4000));
	return 0xFFFF & ioctl(logger, NV_IOC_READ_REG, MK_ADD_VAL(addr + 4, 0));
}
void write_reg(const unsigned short addr, const unsigned short data)
{	
	ioctl(logger, NV_IOC_WRITE_REG, MK_ADD_VAL(addr, data));
}

unsigned short read_reg8(const unsigned short addr)
{	
	return 0xFF & ioctl(logger, NV_IOC_READ_REG, MK_ADD_VAL(addr, 0));
}
unsigned short write_reg8(const unsigned short addr, const unsigned short data)
{	
	ioctl(logger, NV_IOC_WRITE_REG, MK_ADD_VAL(addr, data));
}
